#include "WorldKernel.h"
#include "MessagePort.h"
#include "NetMsg.h"
#include "User.h"
#include "EventMgr.h"
#include "MsgAll.h"
#include "DataBaseMgr.h"

namespace cupid
{

WorldKernel::WorldKernel(void)
{
	loadUsers();
	sEventMgr->registerEvent(event_signup, this, &WorldKernel::onUserSignup);
	sEventMgr->registerEvent(event_signin, this, &WorldKernel::onUserSignin);
	sEventMgr->registerEvent(event_talk, this, &WorldKernel::onUserTalk);
}

WorldKernel::~WorldKernel(void)
{
}
bool WorldKernel::create( IMessagePort* port )
{
	m_pMsgPort		= port;
	m_idProcess		= m_pMsgPort->getID();
	m_pMsgPort->open();
	return true;	
}

//////////////////////////////////////////////////////////////////////
bool WorldKernel::processMsg( int idPacket, void* buf, int type, int from )
{
	switch(idPacket)
	{
	case	KERNEL_CLIENTMSG:
		{
			CLIENTMSG_PACKET0*	msg = (CLIENTMSG_PACKET0*)buf;
			processClientMsg(msg->idSocket, msg->idPacket, msg->buf, msg->size);
		}
		break;
	}
	return true;		
}

//////////////////////////////////////////////////////////////////////
bool WorldKernel::onTimer( time_t curr )
{

	return true;
}

//////////////////////////////////////////////////////////////////////
bool WorldKernel::release()
{
	m_pMsgPort->close();
	delete this;
	return true;	
}

//////////////////////////////////////////////////////////////////////
bool WorldKernel::processClientMsg( int idSocket, int idMsg, const char *buf, int size )
{

	if(idMsg == _MSG_NONE || !buf || size <= 0 || size >_MAX_MSGSIZE)
		return false;

	NetMsg* msg	=NetMsg::createMsg(m_idProcess, idSocket, idMsg, buf, size);
	if(msg)
	{
		try 
		{
			msg->process(this);
		}
		catch(...)
		{
			//			NetMsg::DumpMsg(pMsg);
			ASSERT(!"pMsg->Process(this);");
			log("exception catch at CGameSocket::ProcessMsg()! MsgType:%d, SocketID:%u", idMsg, idSocket);
		}
		delete msg;
	}

	return true;
}

//////////////////////////////////////////////////////////////////////
bool WorldKernel::sendMsg(NetMsg* msg)
{
	ASSERT(msg);
	if(!msg)
		return false;

	return sendMsg(msg->getSocketID(), msg->getType(), msg->getBuf(), msg->getSize());
}

//////////////////////////////////////////////////////////////////////
bool WorldKernel::sendMsg(int idSocket, int idMsg, const char *buf, int len)
{
	if (!buf)
	{
		log("Error: null msg point found in CGameSocket::SendMsg.");
		return false;
	}

	if (_MSG_NONE == idMsg)
	{
		log("Error: invalid msg type in CGameSocket::SendMsg().");
		return false;
	}

	try 
	{
		MESSAGESTR	bufPacket;
		SENDCLIENTMSG_PACKET0* packet = (SENDCLIENTMSG_PACKET0*)bufPacket;
		packet->idSocket	= idSocket;
		packet->idPacket	= idMsg;
		packet->size		= len;
		memcpy(packet->buf, buf, len);
		m_pMsgPort->send(MSGPORT_SOCKET, SOCKET_SENDCLIENTMSG, STRUCT_TYPE(bufPacket), &bufPacket);
		return true;
	}
	catch(...)
	{
		ASSERT(!"catch");
		log("Error: exception catched in CGameSocket::SendMsg().");
		return false;
	}			

	return true;
}

bool WorldKernel::closeSocket(int idSocket)	
{
	m_pMsgPort->send(MSGPORT_SOCKET, SOCKET_BREAKCONNECT, VARTYPE_INT, &idSocket);

	return true;
}

//////////////////////////////////////////////////////////////////////
bool WorldKernel::sendClientMsg( int idSocket, NetMsg* msg )
{
	msg->append(MSGPORT_WORLD, idSocket);
	return sendMsg(msg);
}

User* WorldKernel::newUser(int sock, string name, string password)
{
	if (getUserID(name) != _INVALID_USER_ID)
		return NULL;

	User* user = new User;
	user->setName(name);
	user->setPassword(password);
	user->setGuid(getGUID());
	user->setSock(sock);
	user->onSignup();
	return user;
}
void WorldKernel::addUser(User* user)
{
	m_userList[user->getGuid()] = user;
	m_userName2ID[user->getName()] = user->getGuid();
	if (user->getSock())
	{
		m_userSock2ID[user->getSock()] = user->getGuid();
	}
}
User* WorldKernel::getUser(string name)
{
	return getUser(getUserID(name));
}
User* WorldKernel::getUserBy(int sock)
{
	return getUser(getUserID(sock));
}
User* WorldKernel::getUser(int id)
{
	map<int,User*>::iterator itr =	m_userList.find(id);
	if (itr != m_userList.end())
		return itr->second;
	return NULL;
}
int WorldKernel::getUserID(string name)
{
	map<string,int>::iterator itr =	m_userName2ID.find(name);
	if (itr != m_userName2ID.end())
		return itr->second;
	return _INVALID_USER_ID;
}

int WorldKernel::getUserID(int sock)
{
	map<int,int>::iterator itr = m_userSock2ID.find(sock);
	if (itr != m_userSock2ID.end())
		return itr->second;
	return _INVALID_USER_ID;
}

void WorldKernel::sendFriends(User* user)
{
	map<int,User*>::iterator itr =	m_userList.begin();
	while(itr != m_userList.end())
	{
		User* other = itr->second;
		itr++;
		if (other == user || !other->getSignin())
			continue;
		MsgFriend msg;
		msg.create(other->getName().c_str());
		sendClientMsg(user->getSock(), &msg);
	}
}

void WorldKernel::loadUsers()
{
	ResultSet rs;
	vector<string> row;
	sDataBase << "SELECT * FROM user", rs;
	while(rs.fetch(row))
	{
		User* user = new User;
		user->onLoad(row);
		addUser(user);
	}
}

}